#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define MAX_BUFF_SIZE 4096
#define PORT 6666

int main(int argc, char** argv)
{
    int fdListen, fdConnect;
    char buff[MAX_BUFF_SIZE];
    sockaddr_in serverAddr, clientAddr;
    socklen_t clientLen = sizeof(clientAddr);
    memset(&serverAddr, 0, sizeof(serverAddr));
    memset(&clientAddr, 0, sizeof(clientAddr));

    if ((fdListen = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl((INADDR_ANY));
    serverAddr.sin_port = htons(PORT);

    // avoid Address in use error
    int on = 1;
    if ((setsockopt(fdListen, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
        printf("setsockopt error: %s(errno: %d)\n", strerror(errno), errno);
        return -2;
    }

    if (bind(fdListen, (sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -2;
    }

    if (listen(fdListen, 1) == -1) {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -2;
    }

    printf("========== waiting for client's request ==========\n");
    if ((fdConnect = accept(fdListen, (sockaddr*)&clientAddr, &clientLen)) == -1) {
        printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -3;
    }
    // get client info
    char clientIp[20];
    inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, clientIp, 16);
    printf("connected to host[%s] port[%d]\n", clientIp, ntohs(clientAddr.sin_port));
    while (1) {
        ssize_t n = recv(fdConnect, buff, MAX_BUFF_SIZE, 0);
        if (n <= 0) {
            printf("receive(%d) error: %s(errno: %d)\n", n, strerror(errno), errno);
            break;
        }
        buff[n] = '\0';
        printf("msg received: %s\n", buff);
        if (strcmp(buff, "quit") == 0)
            break;
    }
    close(fdConnect);
    close(fdListen);
    printf("closed\n");

    return 0;
}
